package com.ruoyi.business.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ijpay.alipay.AliPayApi;
import com.ijpay.core.IJPayHttpResponse;
import com.ijpay.core.enums.RequestMethod;
import com.ijpay.core.enums.SignType;
import com.ijpay.core.kit.PayKit;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.unionpay.UnionPayApi;
import com.ijpay.unionpay.enums.ServiceEnum;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.enums.WxApiType;
import com.ijpay.wxpay.enums.WxDomain;
import com.ijpay.wxpay.model.v3.Amount;
import com.ijpay.wxpay.model.v3.UnifiedOrderModel;
import com.ruoyi.business.app.vo.AppPurchaseVo;
import com.ruoyi.business.bo.HcxMerchantProductAddBo;
import com.ruoyi.business.bo.HcxMerchantProductEditBo;
import com.ruoyi.business.bo.HcxMerchantProductQueryBo;
import com.ruoyi.business.domain.*;
import com.ruoyi.business.mapper.*;
import com.ruoyi.business.service.IHcxMerchantProductService;
import com.ruoyi.business.vo.HcxMerchantProductVo;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
import com.ruoyi.common.core.page.PagePlus;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.core.vo.ObsUploadRespVo;
import com.ruoyi.common.exception.CustomException;
import com.ruoyi.common.utils.AssertUtils;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.oss.OssUtils;
import com.ruoyi.common.utils.qrcode.QRCodeUtil;
import com.ruoyi.pay.entity.AliPayBean;
import com.ruoyi.pay.entity.UnionPayBean;
import com.ruoyi.pay.entity.WxPayV3Bean;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 商家商品Service业务层处理
 *
 * @author wsdz
 * @date 2022-08-18
 */
@Service
@AllArgsConstructor
@Slf4j
public class HcxMerchantProductServiceImpl extends ServicePlusImpl<HcxMerchantProductMapper, HcxMerchantProduct> implements IHcxMerchantProductService {

    private final RedisCache redisCache;

    private final OssUtils ossUtils;

    private final HcxMerchantOrderMapper hcxMerchantOrderMapper;

    private final HcxAppUserMapper hcxAppUserMapper;


    private final WxPayV3Bean wxPayV3Bean;

    private final AliPayBean aliPayBean;

    private final UnionPayBean unionPayBean;


    private final HcxUserCouponMapper hcxUserCouponMapper;

    private final HcxMerchantMapper hcxMerchantMapper;

    private final HcxPlatformProfitMapper hcxPlatformProfitMapper;


    @Override
    public HcxMerchantProductVo queryById(Long id) {
        return getVoById(id, HcxMerchantProductVo.class);
    }

    @Override
    public TableDataInfo<HcxMerchantProductVo> queryPageList(HcxMerchantProductQueryBo bo) {
        PagePlus<HcxMerchantProduct, HcxMerchantProductVo> result = pageVo(PageUtils.buildPagePlus(), buildQueryWrapper(bo), HcxMerchantProductVo.class);
        return PageUtils.buildDataInfo(result);
    }

    @Override
    public List<HcxMerchantProductVo> queryList(HcxMerchantProductQueryBo bo) {
        return listVo(buildQueryWrapper(bo), HcxMerchantProductVo.class);
    }

    private LambdaQueryWrapper<HcxMerchantProduct> buildQueryWrapper(HcxMerchantProductQueryBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<HcxMerchantProduct> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getMerchantId() != null, HcxMerchantProduct::getMerchantId, bo.getMerchantId());
        lqw.like(StrUtil.isNotBlank(bo.getMerchantName()), HcxMerchantProduct::getMerchantName, bo.getMerchantName());
        lqw.eq(StrUtil.isNotBlank(bo.getPicUrl()), HcxMerchantProduct::getPicUrl, bo.getPicUrl());
        lqw.like(StrUtil.isNotBlank(bo.getName()), HcxMerchantProduct::getName, bo.getName());
        lqw.eq(StrUtil.isNotBlank(bo.getSummary()), HcxMerchantProduct::getSummary, bo.getSummary());
        lqw.eq(bo.getProPrice() != null, HcxMerchantProduct::getProPrice, bo.getProPrice());
        lqw.eq(StrUtil.isNotBlank(bo.getIntroduce()), HcxMerchantProduct::getIntroduce, bo.getIntroduce());
        lqw.like(StrUtil.isNotBlank(bo.getLabelName()), HcxMerchantProduct::getLabelName, bo.getLabelName());
        lqw.eq(bo.getSaleNum() != null, HcxMerchantProduct::getSaleNum, bo.getSaleNum());
        lqw.eq(bo.getWashTimes() != null, HcxMerchantProduct::getWashTimes, bo.getWashTimes());
        lqw.eq(StrUtil.isNotBlank(bo.getDelFlag()), HcxMerchantProduct::getDelFlag, bo.getDelFlag());
        // 只查询自己的商品
        SysUser user = SecurityUtils.getLoginUser().getUser();
        List<SysRole> roles = user.getRoles();
        List<String> qunList = roles.stream().map(SysRole::getRoleKey).collect(Collectors.toList());
        if (qunList.contains("merchant")) {
            // 查询 hcx_app_user
            HcxAppUser hcxAppUser = hcxAppUserMapper.selectOne(new LambdaQueryWrapper<HcxAppUser>().eq(HcxAppUser::getPhonenumber, user.getPhonenumber()));
            // 查询商家id
            HcxMerchant hcxMerchant = hcxMerchantMapper.selectOne(new LambdaQueryWrapper<HcxMerchant>().eq(HcxMerchant::getUserId, hcxAppUser.getId()));
            if (ObjectUtil.isNotEmpty(hcxMerchant)) {
                lqw.eq(HcxMerchantProduct::getMerchantId, hcxMerchant.getId());
            }
        }
        return lqw;
    }

    @Override
    public Boolean insertByAddBo(HcxMerchantProductAddBo bo) {
        HcxMerchantProduct add = BeanUtil.toBean(bo, HcxMerchantProduct.class);
        validEntityBeforeSave(add);
        return save(add);
    }

    @Override
    public Boolean updateByEditBo(HcxMerchantProductEditBo bo) {
        HcxMerchantProduct update = BeanUtil.toBean(bo, HcxMerchantProduct.class);
        validEntityBeforeSave(update);
        return updateById(update);
    }

    /**
     * 保存前的数据校验
     *
     * @param entity 实体类数据
     */
    private void validEntityBeforeSave(HcxMerchantProduct entity) {
        // 判断商品名称是否存在
        HcxMerchantProduct hcxMerchantProduct = getOne(new LambdaQueryWrapper<HcxMerchantProduct>()
                .eq(HcxMerchantProduct::getName, entity.getName())
                .last("limit 1")
        );
        // 如果是新增操作
        if (ObjectUtil.isEmpty(entity.getId())) {
            AssertUtils.isTrue(ObjectUtil.isEmpty(hcxMerchantProduct), "新增商品名称" + entity.getMerchantName() + ",失败，商品名称已存在");
        } else {
            if (ObjectUtil.isNotEmpty(hcxMerchantProduct) && entity.getId().longValue() != hcxMerchantProduct.getId().longValue()) {
                throw new CustomException("修改商品名称" + entity.getMerchantName() + ",失败，商品名称已存在");
            }
        }
    }

    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return removeByIds(ids);
    }

    @Override
    public String importHcxMerchantProduct(List<HcxMerchantProductVo> hcxMerchantProductList) {
        AssertUtils.isTrue(CollectionUtils.isNotEmpty(hcxMerchantProductList), "导入数据不能为空");
        int successNum = 0;
        for (HcxMerchantProductVo hcxMerchantProduct : hcxMerchantProductList) {
            HcxMerchantProduct add = BeanUtil.toBean(hcxMerchantProduct, HcxMerchantProduct.class);
            save(add);
            successNum++;
        }
        String msg = String.format("导入完成，共计 %d 条数据，成功 %d 条！", hcxMerchantProductList.size(), successNum);
        if (successNum != hcxMerchantProductList.size()) {
            msg = msg + String.format("失败 %d 条！", hcxMerchantProductList.size() - successNum);
        }
        return msg;
    }

    @Override
    @Transactional
    public AppPurchaseVo purchase(HttpServletRequest request, Long productId, Long couponId, String payType) throws Exception {
        AppPurchaseVo appPurchaseVo = new AppPurchaseVo();


        // 查询商品信息
        HcxMerchantProduct product = getById(productId);
        AssertUtils.isTrue(ObjectUtil.isNotEmpty(product), "非法的商品id");

        // 查询用户优惠券信息
        HcxUserCoupon userCoupon = hcxUserCouponMapper.selectById(couponId);


        // 查询当前用户
        HcxAppUser currentUser = hcxAppUserMapper.selectById(SecurityUtils.getUserId());


        //  购买下单
        HcxMerchantOrder hcxMerchantOrder = new HcxMerchantOrder();

        hcxMerchantOrder.setUserId(SecurityUtils.getUserId());
        hcxMerchantOrder.setRealName(currentUser.getRealName());
        hcxMerchantOrder.setMerchantId(product.getMerchantId());
        hcxMerchantOrder.setMerchantName(product.getMerchantName());
        hcxMerchantOrder.setProductId(productId);
        hcxMerchantOrder.setProductName(product.getName());
        hcxMerchantOrder.setPicUrl(product.getPicUrl());
        hcxMerchantOrder.setSummary(product.getSummary());
        hcxMerchantOrder.setProPrice(product.getProPrice());
        hcxMerchantOrder.setProNum(1L);


        // 应付金额
        hcxMerchantOrder.setShouldPrice(product.getProPrice().setScale(2, BigDecimal.ROUND_HALF_UP));
        // 实付金额= 商品价格-优惠券面额
        if (ObjectUtil.isNotEmpty(userCoupon)) {
            hcxMerchantOrder.setActualPrice(product.getProPrice().subtract(userCoupon.getDenomination()).setScale(2, BigDecimal.ROUND_HALF_UP));
            hcxMerchantOrder.setUserCouponId(couponId);
            hcxMerchantOrder.setDenomination(userCoupon.getDenomination());
            hcxMerchantOrder.setConditionPrice(userCoupon.getConditionPrice());
            hcxMerchantOrder.setUseIntroduce(userCoupon.getUseIntroduce());
        } else {
            // 实付金额=应付金额
            hcxMerchantOrder.setActualPrice(hcxMerchantOrder.getShouldPrice());
        }

        hcxMerchantOrder.setStatus(Constants.ZERO);
        // 洗车次数
        hcxMerchantOrder.setWashTimes(Integer.valueOf(Constants.ONE));
        // 剩余洗车次数
        hcxMerchantOrder.setSurplusTimes(Integer.valueOf(Constants.ONE));
        // 订单类型
        hcxMerchantOrder.setOrderType(Constants.ZERO);
        // 支付方式
        hcxMerchantOrder.setPayType(payType);
        // 生成订单编号 如果是单次 则以 YC开头+年月日时分秒毫秒+5位随机数   如果是洗车卡 则以 DC+年月日时分秒毫秒+5位随机数
        String format = DateUtil.format(new Date(), "yyyyMMddHHmmss");
        String numbers = RandomUtil.randomNumbers(5);
        String orderNum = "YC" + format + numbers;
        hcxMerchantOrder.setOrderNum(orderNum);

        // 应付金额转换为分
        int fen = hcxMerchantOrder.getActualPrice().movePointRight(2).intValue();

        int bijiao = hcxMerchantOrder.getActualPrice().compareTo(new BigDecimal(0));


        // 大于0
        if (bijiao == 1) {

            // 微信支付
            if (Constants.ONE.equals(payType)) {

                UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
                        .setAppid(wxPayV3Bean.getAppId())
                        .setMchid(wxPayV3Bean.getMchId())
                        .setDescription("购买商品(" + product.getName() + ")")
                        .setOut_trade_no(orderNum)
                        .setAttach("微信支付方式支付")
                        .setNotify_url(wxPayV3Bean.getDomain().concat(wxPayV3Bean.getNotifyUrl()))
                        .setAmount(new Amount().setTotal(fen));

                log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
                IJPayHttpResponse response = WxPayApi.v3(
                        RequestMethod.POST,
                        WxDomain.CHINA.toString(),
                        WxApiType.APP_PAY.toString(),
                        wxPayV3Bean.getMchId(),
                        getSerialNumber(),
                        getPlatSerialNumber(),
                        wxPayV3Bean.getKeyPath(),
                        JSONUtil.toJsonStr(unifiedOrderModel)
                );
                log.info("统一下单响应 {}", response);
                // 根据证书序列号查询对应的证书来验证签名结果
                boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
                if (verifySignature) {
                    JSONObject entries = JSONUtil.parseObj(response.getBody());
                    String prepayId = entries.getStr("prepay_id");
                    log.info("预支付的id为--------》{}", prepayId);
                    Map<String, String> orderMap = WxPayKit.appCreateSign(wxPayV3Bean.getAppId(), wxPayV3Bean.getMchId(), prepayId, wxPayV3Bean.getKeyPath());
                    appPurchaseVo.setOrderInfo(orderMap);
                }
                // todo 相关业务处理在回调中处理
            } else if (Constants.TWO.equals(payType)) {
                // 支付宝支付

                AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
                model.setBody("支付宝支付");
                model.setSubject("购买商品(" + product.getName() + ")");
                model.setOutTradeNo(orderNum);
                model.setTotalAmount(hcxMerchantOrder.getActualPrice().toString());
                String orderInfo = AliPayApi.appPayToResponse(model, aliPayBean.getDomain().concat(aliPayBean.getNotifyUrl())).getBody();
                log.info("支付宝下单 {}", orderInfo);
                Map<String, String> orderMap = new HashMap<>();
                orderMap.put("orderInfo", orderInfo);
                appPurchaseVo.setOrderInfo(orderMap);

            } else if (Constants.THREE.equals(payType)) {
                // 银联支付

                String notifyUrl = unionPayBean.getDomain().concat(unionPayBean.getNotifyUrl());
                String ip = ServletUtil.getClientIP(request);

                Map<String, String> params = com.ijpay.unionpay.model.UnifiedOrderModel.builder()
                        .service(ServiceEnum.NATIVE.toString())
                        .mch_id(unionPayBean.getMachId())
                        .out_trade_no(WxPayKit.generateStr())
                        .body("IJPay 云闪付-扫码支付")
                        .attach("聚合支付 SDK")
                        .total_fee(String.valueOf(fen))
                        .mch_create_ip(ip)
                        .notify_url(notifyUrl)
                        .nonce_str(WxPayKit.generateStr())
                        .build()
                        .createSign(unionPayBean.getKey(), SignType.MD5);

                String xmlResult = UnionPayApi.execution(unionPayBean.getServerUrl(), params);
                log.info("xmlResult:" + xmlResult);
                Map<String, String> result = WxPayKit.xmlToMap(xmlResult);


            } else {
                // 如果是余额支付
                AssertUtils.isTrue(currentUser.getBalancePrice().compareTo(hcxMerchantOrder.getActualPrice()) != -1, "余额不足");
                // 金额-订单实付金额
                currentUser.setBalancePrice(currentUser.getBalancePrice().subtract(hcxMerchantOrder.getActualPrice()).setScale(2, BigDecimal.ROUND_HALF_UP));

                hcxMerchantOrder.setStatus(Constants.ONE);

                hcxAppUserMapper.updateById(currentUser);

                // 优惠券状态改为已使用
                if (ObjectUtil.isNotEmpty(userCoupon)) {
                    userCoupon.setStatus(Constants.ONE);
                    hcxUserCouponMapper.updateById(userCoupon);
                }


            }
        } else {
            // 如果 小于等于0

            hcxMerchantOrder.setStatus(Constants.ONE);

            hcxAppUserMapper.updateById(currentUser);

            // 优惠券状态改为已使用
            if (ObjectUtil.isNotEmpty(userCoupon)) {
                userCoupon.setStatus(Constants.ONE);
                hcxUserCouponMapper.updateById(userCoupon);
            }


        }


        // 设置logo小图标
        String logoAddress = redisCache.getCacheObject(Constants.SYS_CONFIG_KEY + Constants.QRCODE_LOGO_ADDRESS);
        AssertUtils.isNotBlank(logoAddress, "logo地址还没有配置,请后台配置!");
        // 分享二维码存放目录
        String destPath = redisCache.getCacheObject(Constants.SYS_CONFIG_KEY + Constants.QRCODE_DESC_ADDRESS);
        AssertUtils.isNotBlank(destPath, "二维码存放地址还没有配置,请后台配置!");


        // 生成二维码
        MultipartFile multipartFile = QRCodeUtil.encode(hcxMerchantOrder.getOrderNum(), logoAddress, destPath, true);
        // 文件上传
        ObsUploadRespVo obsUploadRespVo = ossUtils.uploadMultipartFile(multipartFile);
        hcxMerchantOrder.setQrCode(obsUploadRespVo.getObjectUrl());
        hcxMerchantOrderMapper.insert(hcxMerchantOrder);

        appPurchaseVo.setQrCode(obsUploadRespVo.getObjectUrl());


        return appPurchaseVo;
    }

    private String getSerialNumber() {
        // 获取证书序列号
        X509Certificate certificate = PayKit.getCertificate(FileUtil.getInputStream(wxPayV3Bean.getCertPath()));
        String serialNo = certificate.getSerialNumber().toString(16).toUpperCase();
        log.info("证书系列号为--->{}", serialNo);
        return serialNo;
    }

    private String getPlatSerialNumber() {
        // 获取平台证书序列号
        X509Certificate certificate = PayKit.getCertificate(FileUtil.getInputStream(wxPayV3Bean.getPlatformCertPath()));
        String platSerialNo = certificate.getSerialNumber().toString(16).toUpperCase();
        log.info("平台系列号为--->{}", platSerialNo);
        return platSerialNo;
    }

}
